home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 June / PersonalComputerWorld-June2009-CoverdiscCD.iso / Software / Freeware / Firebug 1.3.3 / firebug-1.3.3-fx.xpi / content / firebug / inspector.js < prev    next >
Encoding:
JavaScript  |  2009-02-19  |  24.3 KB  |  796 lines

  1. 8/29/2007/* See license.txt for terms of usage */
  2.  
  3. FBL.ns(function() { with (FBL) {
  4.  
  5. // ************************************************************************************************
  6. // Constants
  7.  
  8. const inspectDelay = 100;
  9.  
  10. const edgeSize = 2;
  11.  
  12. const defaultPrimaryPanel = "html";
  13. const defaultSecondaryPanel = "dom";
  14.  
  15. const highlightCSS = "chrome://firebug/content/highlighter.css";
  16.  
  17. // ************************************************************************************************
  18. // Globals
  19.  
  20. var boxModelHighlighter = null;
  21. var frameHighlighter = null;
  22. var popupHighlighter = null;
  23.  
  24. // ************************************************************************************************
  25.  
  26. Firebug.Inspector = extend(Firebug.Module,
  27. {
  28.     inspecting: false,
  29.  
  30.     highlightObject: function(element, context, highlightType, boxFrame)
  31.     {
  32.         if (!element || !isElement(element) || !isVisible(element))
  33.             element = null;
  34.  
  35.         if (element && context && context.highlightTimeout)
  36.         {
  37.             context.clearTimeout(context.highlightTimeout);
  38.             delete context.highlightTimeout;
  39.         }
  40.  
  41.         var highlighter = highlightType ? getHighlighter(highlightType) : this.defaultHighlighter;
  42.  
  43.         var oldContext = this.highlightedContext;
  44.         if (oldContext && highlighter != this.highlighter)
  45.         {
  46.             if (oldContext.window)
  47.                 this.highlighter.unhighlight(oldContext);
  48.         }
  49.  
  50.         this.highlighter = highlighter;
  51.         this.highlightedElement = element;
  52.         this.highlightedContext = context;
  53.  
  54.         if (element)
  55.         {
  56.             if (context && context.window && context.window.document)
  57.                 highlighter.highlight(context, element, boxFrame);
  58.         }
  59.         else if (oldContext)
  60.         {
  61.             oldContext.highlightTimeout = oldContext.setTimeout(function()
  62.             {
  63.                 delete oldContext.highlightTimeout;
  64.                 if (oldContext.window && oldContext.window.document)
  65.                     highlighter.unhighlight(oldContext);
  66.             }, inspectDelay);
  67.         }
  68.     },
  69.  
  70.     toggleInspecting: function(context)
  71.     {
  72.         if (this.inspecting)
  73.             this.stopInspecting(true);
  74.         else
  75.             this.startInspecting(context);
  76.     },
  77.  
  78.     startInspecting: function(context)
  79.     {
  80.         if (this.inspecting || !context || !context.loaded)
  81.             return;
  82.  
  83.         this.inspecting = true;
  84.         this.inspectingContext = context;
  85.  
  86.         context.chrome.setGlobalAttribute("cmd_toggleInspecting", "checked", "true");
  87.         this.attachInspectListeners(context);
  88.  
  89.         // Remember the previous panel and bar state so we can revert if the user cancels
  90.         this.previousPanelName = context.panelName;
  91.         this.previousSidePanelName = context.sidePanelName;
  92.         this.previouslyCollapsed = $("fbContentBox").collapsed;
  93.         this.previouslyFocused = context.detached && context.chrome.isFocused();
  94.  
  95.         var htmlPanel = context.chrome.selectPanel("html");
  96.         this.previousObject = htmlPanel.selection;
  97.  
  98.         if (context.detached)
  99.             FirebugChrome.focus();
  100.         else
  101.             Firebug.showBar(true);
  102.  
  103.         htmlPanel.panelNode.focus();
  104.         htmlPanel.startInspecting();
  105.  
  106.         if (context.hoverNode)
  107.             this.inspectNode(context.hoverNode);
  108.     },
  109.  
  110.     inspectNode: function(node)
  111.     {
  112.         if (node && node.nodeType != 1)
  113.             node = node.parentNode;
  114.  
  115.         if (node && node.firebugIgnore)
  116.             return;
  117.  
  118.         var context = this.inspectingContext;
  119.  
  120.         if (this.inspectTimeout)
  121.         {
  122.             context.clearTimeout(this.inspectTimeout);
  123.             delete this.inspectTimeout;
  124.         }
  125.  
  126.         this.highlightObject(node, context, "frame");
  127.  
  128.         this.inspectingNode = node;
  129.  
  130.         if (node)
  131.         {
  132.             this.inspectTimeout = context.setTimeout(function()
  133.             {
  134.                 if (context.chrome)
  135.                     context.chrome.select(node);
  136.             }, inspectDelay);
  137.         }
  138.     },
  139.  
  140.     stopInspecting: function(cancelled, waitForClick)
  141.     {
  142.         if (!this.inspecting)
  143.             return;
  144.  
  145.         var context = this.inspectingContext;
  146.  
  147.         if (this.inspectTimeout)
  148.         {
  149.             context.clearTimeout(this.inspectTimeout);
  150.             delete this.inspectTimeout;
  151.         }
  152.  
  153.         this.detachInspectListeners(context);
  154.         if (!waitForClick)
  155.             this.detachClickInspectListeners(context.window);
  156.  
  157.         context.chrome.setGlobalAttribute("cmd_toggleInspecting", "checked", "false");
  158.  
  159.         this.inspecting = false;
  160.  
  161.         var htmlPanel = context.getPanel("html");
  162.  
  163.         if (this.previouslyFocused)
  164.             context.chrome.focus();
  165.  
  166.         if (cancelled)
  167.         {
  168.             if (this.previouslyCollapsed)
  169.                 Firebug.showBar(false);
  170.  
  171.             if (this.previousPanelName == "html")
  172.                 context.chrome.select(this.previousObject);
  173.             else
  174.                 context.chrome.selectPanel(this.previousPanelName, this.previousSidePanelName);
  175.         }
  176.         else
  177.         {
  178.             context.chrome.select(htmlPanel.selection);
  179.             context.chrome.getSelectedPanel().panelNode.focus();
  180.         }
  181.  
  182.         htmlPanel.stopInspecting(htmlPanel.selection, cancelled);
  183.  
  184.         this.inspectNode(null);
  185.  
  186.         delete this.previousObject;
  187.         delete this.previousPanelName;
  188.         delete this.previousSidePanelName;
  189.         delete this.inspectingContext;
  190.     },
  191.  
  192.     inspectNodeBy: function(dir)
  193.     {
  194.         var target;
  195.         var node = this.inspectingNode;
  196.  
  197.         if (dir == "up")
  198.             target = this.inspectingContext.chrome.getNextObject();
  199.         else if (dir == "down")
  200.         {
  201.             target = this.inspectingContext.chrome.getNextObject(true);
  202.             if (node && !target)
  203.             {
  204.                 if (node.contentDocument)
  205.                     target = node.contentDocument.documentElement;
  206.                 else
  207.                     target = getNextElement(node.firstChild);
  208.             }
  209.         }
  210.  
  211.         if (target && isElement(target))
  212.             this.inspectNode(target);
  213.         else
  214.             beep();
  215.     },
  216.  
  217.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  218.  
  219.     attachInspectListeners: function(context)
  220.     {
  221.         var win = context.window;
  222.         if (!win || !win.document)
  223.             return;
  224.  
  225.         var chrome = context.chrome;
  226.         if (!chrome)
  227.             chrome = FirebugChrome;
  228.  
  229.         this.keyListeners =
  230.         [
  231.             chrome.keyCodeListen("RETURN", null, bindFixed(this.stopInspecting, this)),
  232.             chrome.keyCodeListen("ESCAPE", null, bindFixed(this.stopInspecting, this, true)),
  233.             chrome.keyCodeListen("UP", isControl, bindFixed(this.inspectNodeBy, this, "up"), true),
  234.             chrome.keyCodeListen("DOWN", isControl, bindFixed(this.inspectNodeBy, this, "down"), true),
  235.         ];
  236.  
  237.         iterateWindows(win, bind(function(subWin)
  238.         {
  239.             subWin.document.addEventListener("mouseover", this.onInspectingMouseOver, true);
  240.             subWin.document.addEventListener("mousedown", this.onInspectingMouseDown, true);
  241.             subWin.document.addEventListener("click", this.onInspectingClick, true);
  242.         }, this));
  243.     },
  244.  
  245.     detachInspectListeners: function(context)
  246.     {
  247.         var win = context.window;
  248.         if (!win || !win.document)
  249.             return;
  250.  
  251.         var chrome = context.chrome;
  252.         if (!chrome)
  253.             chrome = FirebugChrome;
  254.  
  255.         if (this.keyListeners)  // XXXjjb for some reason this is null some times.
  256.         {
  257.             for (var i = 0; i < this.keyListeners.length; ++i)
  258.                 chrome.keyIgnore(this.keyListeners[i]);
  259.             delete this.keyListeners;
  260.         }
  261.  
  262.         iterateWindows(win, bind(function(subWin)
  263.         {
  264.             subWin.document.removeEventListener("mouseover", this.onInspectingMouseOver, true);
  265.             subWin.document.removeEventListener("mousedown", this.onInspectingMouseDown, true);
  266.         }, this));
  267.     },
  268.  
  269.     detachClickInspectListeners: function(win)
  270.     {
  271.         // We have to remove the click listener in a second phase because if we remove it
  272.         // after the mousedown, we won't be able to cancel clicked links
  273.         iterateWindows(win, bind(function(subWin)
  274.         {
  275.             subWin.document.removeEventListener("click", this.onInspectingClick, true);
  276.         }, this));
  277.     },
  278.  
  279.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  280.  
  281.     onInspectingMouseOver: function(event)
  282.     {
  283.         this.inspectNode(event.target);
  284.         cancelEvent(event);
  285.     },
  286.  
  287.     onInspectingMouseDown: function(event)
  288.     {
  289.         this.stopInspecting(false, true);
  290.         cancelEvent(event);
  291.     },
  292.  
  293.     onInspectingClick: function(event)
  294.     {
  295.         var win = event.currentTarget.defaultView;
  296.         if (win)
  297.         {
  298.             win = getRootWindow(win);
  299.             this.detachClickInspectListeners(win);
  300.         }
  301.         cancelEvent(event);
  302.     },
  303.  
  304.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  305.     // extends Module
  306.  
  307.     initialize: function()
  308.     {
  309.         this.onInspectingMouseOver = bind(this.onInspectingMouseOver, this);
  310.         this.onInspectingMouseDown = bind(this.onInspectingMouseDown, this);
  311.         this.onInspectingClick = bind(this.onInspectingClick, this);
  312.  
  313.         this.updateOption("shadeBoxModel", Firebug.shadeBoxModel);
  314.     },
  315.  
  316.     initContext: function(context)
  317.     {
  318.         context.onPreInspectMouseOver = function(event) { context.hoverNode = event.target; };
  319.     },
  320.  
  321.     destroyContext: function(context)
  322.     {
  323.         if (context.highlightTimeout)
  324.         {
  325.             context.clearTimeout(context.highlightTimeout);
  326.             delete context.highlightTimeout;
  327.         }
  328.  
  329.         if (this.inspecting)
  330.             this.stopInspecting(true);
  331.     },
  332.  
  333.     watchWindow: function(context, win)
  334.     {
  335.         win.addEventListener("mouseover", context.onPreInspectMouseOver, true);
  336.     },
  337.  
  338.     unwatchWindow: function(context, win)
  339.     {
  340.         try {
  341.             win.removeEventListener("mouseover", context.onPreInspectMouseOver, true);
  342.         } catch (ex) {
  343.             // Get unfortunate errors here sometimes, so let's just ignore them
  344.             // since the window is going away anyhow
  345.         }
  346.     },
  347.  
  348.     showContext: function(browser, context)
  349.     {
  350.         if (this.inspecting)
  351.             this.stopInspecting(true);
  352.  
  353.         if (browser)
  354.         {
  355.             var disabled = !context || !context.loaded;
  356.             browser.chrome.setGlobalAttribute("menu_firebugInspect", "disabled", disabled);
  357.         }
  358.     },
  359.  
  360.     showPanel: function(browser, panel)
  361.     {
  362.         var chrome = browser.chrome;
  363.         var disabled = !panel || !panel.context.loaded;
  364.         chrome.setGlobalAttribute("cmd_toggleInspecting", "disabled", disabled);
  365.         chrome.setGlobalAttribute("menu_firebugInspect", "disabled", disabled);
  366.     },
  367.  
  368.     loadedContext: function(context)
  369.     {
  370.         context.chrome.setGlobalAttribute("cmd_toggleInspecting", "disabled", "false");
  371.         context.chrome.setGlobalAttribute("menu_firebugInspect", "disabled", "false");
  372.     },
  373.  
  374.     updateOption: function(name, value)
  375.     {
  376.         if (name == "shadeBoxModel")
  377.         {
  378.             this.highlightObject(null);
  379.             this.defaultHighlighter = value ? getHighlighter("boxModel") : getHighlighter("frame");
  380.         }
  381.     },
  382.  
  383.     getObjectByURL: function(context, url)
  384.     {
  385.         var styleSheet = getStyleSheetByHref(url, context);
  386.         if (styleSheet)
  387.             return styleSheet;
  388.  
  389.         /*var path = getURLPath(url);
  390.         var xpath = "//*[contains(@src, '" + path + "')]";
  391.         var elements = getElementsByXPath(context.window.document, xpath);
  392.         if (elements.length)
  393.             return elements[0];*/
  394.     }
  395. });
  396.  
  397. // ************************************************************************************************
  398. // Local Helpers
  399.  
  400. function getHighlighter(type)
  401. {
  402.     if (type == "boxModel")
  403.     {
  404.         if (!boxModelHighlighter)
  405.             boxModelHighlighter = new BoxModelHighlighter();
  406.  
  407.         return boxModelHighlighter;
  408.     }
  409.     else if (type == "frame")
  410.     {
  411.         if (!frameHighlighter)
  412.             frameHighlighter = new FrameHighlighter();
  413.  
  414.         return frameHighlighter;
  415.     }
  416.     else if (type == "popup")
  417.     {
  418.         if (!popupHighlighter)
  419.             popupHighlighter = new PopupHighlighter();
  420.  
  421.         return popupHighlighter;
  422.     }
  423. }
  424.  
  425. function pad(element, t, r, b, l)
  426. {
  427.     element.style.padding = Math.abs(t) + "px " + Math.abs(r) + "px "
  428.         + Math.abs(b) + "px " + Math.abs(l) + "px";
  429. }
  430.  
  431. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  432.  
  433. function FrameHighlighter()
  434. {
  435. }
  436.  
  437. FrameHighlighter.prototype =
  438. {
  439.     highlight: function(context, element)
  440.     {
  441.         if (element instanceof XULElement)
  442.             return;
  443.         var offset = getViewOffset(element, true);
  444.         var x = offset.x, y = offset.y;
  445.         var w = element.offsetWidth, h = element.offsetHeight;
  446.         var wacked = isNaN(x) || isNaN(y) || isNaN(w) || isNaN(h);
  447.         if (wacked)
  448.             return;
  449.  
  450.         var nodes = this.getNodes(context, element);
  451.  
  452.         move(nodes.top, x, y-edgeSize);
  453.         resize(nodes.top, w, edgeSize);
  454.  
  455.         move(nodes.right, x+w, y-edgeSize);
  456.         resize(nodes.right, edgeSize, h+edgeSize*2);
  457.  
  458.         move(nodes.bottom, x, y+h);
  459.         resize(nodes.bottom, w, edgeSize);
  460.  
  461.         move(nodes.left, x-edgeSize, y-edgeSize);
  462.         resize(nodes.left, edgeSize, h+edgeSize*2);
  463.         var body = getNonFrameBody(element);
  464.         if (!body)
  465.             return this.unhighlight(context);
  466.  
  467.         var needsAppend = !nodes.top.parentNode || nodes.top.ownerDocument != body.ownerDocument;
  468.         if (needsAppend)
  469.         {
  470.             attachStyles(context, body);
  471.             for (var edge in nodes)
  472.             {
  473.                 try
  474.                 {
  475.                     body.appendChild(nodes[edge]);
  476.                 }
  477.                 catch(exc)
  478.                 {
  479.                 }
  480.             }
  481.         }
  482.     },
  483.  
  484.     unhighlight: function(context)
  485.     {
  486.         var nodes = this.getNodes(context);
  487.         var body = nodes.top.parentNode;
  488.         if (body)
  489.         {
  490.             for (var edge in nodes)
  491.                 body.removeChild(nodes[edge]);
  492.         }
  493.     },
  494.  
  495.     getNodes: function(context)
  496.     {
  497.         if (!context.frameHighlighter)
  498.         {
  499.             var doc = context.window.document;
  500.  
  501.             function createEdge(name)
  502.             {
  503.                 var div = doc.createElementNS("http://www.w3.org/1999/xhtml", "div");
  504.                 div.firebugIgnore = true;
  505.                 div.className = "firebugHighlight";
  506.                 return div;
  507.             }
  508.  
  509.             context.frameHighlighter =
  510.             {
  511.                 top: createEdge("Top"),
  512.                 right: createEdge("Right"),
  513.                 bottom: createEdge("Bottom"),
  514.                 left: createEdge("Left")
  515.             };
  516.         }
  517.  
  518.         return context.frameHighlighter;
  519.     }
  520. };
  521. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  522.  
  523. function PopupHighlighter()
  524. {
  525. }
  526.  
  527. PopupHighlighter.prototype =
  528. {
  529.     highlight: function(context, element)
  530.     {
  531.         var doc = context.window.document;
  532.         var popup = doc.getElementById("inspectorPopup");
  533.         popup.style.width = "200px";
  534.         popup.style.height = "100px";
  535.         popup.showPopup(element, element.boxObject.screenX,
  536.             element.boxObject.screenY, "popup", "none", "none");
  537.     },
  538.  
  539.     unhighlight: function(context)
  540.     {
  541.     },
  542. }
  543. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  544.  
  545. function BoxModelHighlighter()
  546. {
  547. }
  548.  
  549. BoxModelHighlighter.prototype =
  550. {
  551.     highlight: function(context, element, boxFrame)
  552.     {
  553.         var nodes = this.getNodes(context);
  554.         var highlightFrame = boxFrame ? nodes[boxFrame] : null;
  555.  
  556.         if (context.highlightFrame)
  557.             removeClass(context.highlightFrame, "firebugHighlightBox");
  558.  
  559.         context.highlightFrame = highlightFrame;
  560.  
  561.         if (highlightFrame)
  562.         {
  563.             setClass(nodes.offset, "firebugHighlightGroup");
  564.             setClass(highlightFrame, "firebugHighlightBox");
  565.         }
  566.         else
  567.             removeClass(nodes.offset, "firebugHighlightGroup");
  568.  
  569.         var win = element.ownerDocument.defaultView;
  570.         if (!win)
  571.             return;
  572.  
  573.         var offsetParent = element.offsetParent;
  574.         if (!offsetParent)
  575.             return;
  576.  
  577.         var parentStyle = win.getComputedStyle(offsetParent, "");
  578.         var parentOffset = getViewOffset(offsetParent, true);
  579.         var parentX = parentOffset.x + parseInt(parentStyle.borderLeftWidth);
  580.         var parentY = parentOffset.y + parseInt(parentStyle.borderTopWidth);
  581.         var parentW = offsetParent.offsetWidth-1;
  582.         var parentH = offsetParent.offsetHeight-1;
  583.  
  584.         var style = win.getComputedStyle(element, "");
  585.         var styles = readBoxStyles(style);
  586.  
  587.         var offset = getViewOffset(element, true);
  588.         var x = offset.x - Math.abs(styles.marginLeft);
  589.         var y = offset.y - Math.abs(styles.marginTop);
  590.         var w = element.offsetWidth - (styles.paddingLeft + styles.paddingRight
  591.                 + styles.borderLeft + styles.borderRight);
  592.         var h = element.offsetHeight - (styles.paddingTop + styles.paddingBottom
  593.                 + styles.borderTop + styles.borderBottom);
  594.  
  595.         move(nodes.offset, x, y);
  596.         pad(nodes.margin, styles.marginTop, styles.marginRight, styles.marginBottom,
  597.                 styles.marginLeft);
  598.         pad(nodes.border, styles.borderTop, styles.borderRight, styles.borderBottom,
  599.                 styles.borderLeft);
  600.         pad(nodes.padding, styles.paddingTop, styles.paddingRight, styles.paddingBottom,
  601.                 styles.paddingLeft);
  602.         resize(nodes.content, w, h);
  603.  
  604.         var showLines = Firebug.showRulers && boxFrame;
  605.         if (showLines)
  606.         {
  607.             move(nodes.parent, parentX, parentY);
  608.             resize(nodes.parent, parentW, parentH);
  609.  
  610.             if (parentX < 14)
  611.                 setClass(nodes.parent, "overflowRulerX");
  612.             else
  613.                 removeClass(nodes.parent, "overflowRulerX");
  614.  
  615.             if (parentY < 14)
  616.                 setClass(nodes.parent, "overflowRulerY");
  617.             else
  618.                 removeClass(nodes.parent, "overflowRulerY");
  619.  
  620.             var left = x;
  621.             var top = y;
  622.             var width = w-1;
  623.             var height = h-1;
  624.  
  625.             if (boxFrame == "content")
  626.             {
  627.                 left += Math.abs(styles.marginLeft) + Math.abs(styles.borderLeft)
  628.                     + Math.abs(styles.paddingLeft);
  629.                 top += Math.abs(styles.marginTop) + Math.abs(styles.borderTop)
  630.                     + Math.abs(styles.paddingTop);
  631.             }
  632.             else if (boxFrame == "padding")
  633.             {
  634.                 left += Math.abs(styles.marginLeft) + Math.abs(styles.borderLeft);
  635.                 top += Math.abs(styles.marginTop) + Math.abs(styles.borderTop);
  636.                 width += Math.abs(styles.paddingLeft) + Math.abs(styles.paddingRight);
  637.                 height += Math.abs(styles.paddingTop) + Math.abs(styles.paddingBottom);
  638.             }
  639.             else if (boxFrame == "border")
  640.             {
  641.                 left += Math.abs(styles.marginLeft);
  642.                 top += Math.abs(styles.marginTop);
  643.                 width += Math.abs(styles.paddingLeft) + Math.abs(styles.paddingRight)
  644.                      + Math.abs(styles.borderLeft) + Math.abs(styles.borderRight);
  645.                 height += Math.abs(styles.paddingTop) + Math.abs(styles.paddingBottom)
  646.                     + Math.abs(styles.borderTop) + Math.abs(styles.borderBottom);
  647.             }
  648.             else if (boxFrame == "margin")
  649.             {
  650.                 width += Math.abs(styles.paddingLeft) + Math.abs(styles.paddingRight)
  651.                      + Math.abs(styles.borderLeft) + Math.abs(styles.borderRight)
  652.                      + Math.abs(styles.marginLeft) + Math.abs(styles.marginRight);
  653.                 height += Math.abs(styles.paddingTop) + Math.abs(styles.paddingBottom)
  654.                     + Math.abs(styles.borderTop) + Math.abs(styles.borderBottom)
  655.                     + Math.abs(styles.marginTop) + Math.abs(styles.marginBottom);
  656.             }
  657.  
  658.             move(nodes.lines.top, 0, top);
  659.             move(nodes.lines.right, left+width, 0);
  660.             move(nodes.lines.bottom, 0, top+height);
  661.             move(nodes.lines.left, left, 0)
  662.         }
  663.  
  664.         var body = getNonFrameBody(element);
  665.         if (!body)
  666.             return this.unhighlight(context);
  667.  
  668.         var needsAppend = !nodes.offset.parentNode
  669.             || nodes.offset.parentNode.ownerDocument != body.ownerDocument;
  670.  
  671.         if (needsAppend)
  672.         {
  673.             attachStyles(context, body);
  674.             body.appendChild(nodes.offset);
  675.         }
  676.  
  677.         if (showLines)
  678.         {
  679.             if (!nodes.lines.top.parentNode)
  680.             {
  681.                 body.appendChild(nodes.parent);
  682.  
  683.                 for (var line in nodes.lines)
  684.                     body.appendChild(nodes.lines[line]);
  685.             }
  686.         }
  687.         else if (nodes.lines.top.parentNode)
  688.         {
  689.             body.removeChild(nodes.parent);
  690.  
  691.             for (var line in nodes.lines)
  692.                 body.removeChild(nodes.lines[line]);
  693.         }
  694.     },
  695.  
  696.     unhighlight: function(context)
  697.     {
  698.         var nodes = this.getNodes(context);
  699.         if (nodes.offset.parentNode)
  700.         {
  701.             var body = nodes.offset.parentNode;
  702.             body.removeChild(nodes.offset);
  703.  
  704.             if (nodes.lines.top.parentNode)
  705.             {
  706.                 body.removeChild(nodes.parent);
  707.  
  708.                 for (var line in nodes.lines)
  709.                     body.removeChild(nodes.lines[line]);
  710.             }
  711.         }
  712.     },
  713.  
  714.     getNodes: function(context)
  715.     {
  716.         if (!context.boxModelHighlighter)
  717.         {
  718.             var doc = context.window.document;
  719.             function createRuler(name)
  720.             {
  721.                 var div = doc.createElementNS("http://www.w3.org/1999/xhtml", "div");
  722.                 div.firebugIgnore = true;
  723.                 div.className = "firebugRuler firebugRuler"+name;
  724.                 return div;
  725.             }
  726.  
  727.             function createBox(name)
  728.             {
  729.                 var div = doc.createElementNS("http://www.w3.org/1999/xhtml", "div");
  730.                 div.firebugIgnore = true;
  731.                 div.className = "firebugLayoutBox firebugLayoutBox"+name;
  732.                 return div;
  733.             }
  734.  
  735.             function createLine(name)
  736.             {
  737.                 var div = doc.createElementNS("http://www.w3.org/1999/xhtml", "div");
  738.                 div.firebugIgnore = true;
  739.                 div.className = "firebugLayoutLine firebugLayoutLine"+name;
  740.                 return div;
  741.             }
  742.  
  743.             var nodes = context.boxModelHighlighter =
  744.             {
  745.                 parent: createBox("Parent"),
  746.                 rulerH: createRuler("H"),
  747.                 rulerV: createRuler("V"),
  748.                 offset: createBox("Offset"),
  749.                 margin: createBox("Margin"),
  750.                 border: createBox("Border"),
  751.                 padding: createBox("Padding"),
  752.                 content: createBox("Content"),
  753.                 lines: {
  754.                     top: createLine("Top"),
  755.                     right: createLine("Right"),
  756.                     bottom: createLine("Bottom"),
  757.                     left: createLine("Left")
  758.                 }
  759.             };
  760.  
  761.             nodes.parent.appendChild(nodes.rulerH);
  762.             nodes.parent.appendChild(nodes.rulerV);
  763.             nodes.offset.appendChild(nodes.margin);
  764.             nodes.margin.appendChild(nodes.border);
  765.             nodes.border.appendChild(nodes.padding);
  766.             nodes.padding.appendChild(nodes.content);
  767.         }
  768.  
  769.         return context.boxModelHighlighter;
  770.     }
  771. };
  772.  
  773. function getNonFrameBody(elt)
  774. {
  775.     var body = getBody(elt.ownerDocument);
  776.     return body.localName.toUpperCase() == "FRAMESET" ? null : body;
  777. }
  778.  
  779. function attachStyles(context, body)
  780. {
  781.     var doc = body.ownerDocument;
  782.     if (!context.highlightStyle)
  783.         context.highlightStyle = createStyleSheet(doc, highlightCSS);
  784.  
  785.     if (!context.highlightStyle.parentNode || context.highlightStyle.ownerDocument != doc)
  786.         addStyleSheet(body.ownerDocument, context.highlightStyle);
  787. }
  788.  
  789. // ************************************************************************************************
  790.  
  791. Firebug.registerModule(Firebug.Inspector);
  792.  
  793. // ************************************************************************************************
  794.  
  795. }});
  796.